#!/bin/bash

# SSL/TLS证书设置脚本
# 用于生成自签名证书或配置Let's Encrypt证书

set -e

# 配置
DOMAIN=${DOMAIN:-localhost}
SSL_DIR="./config/ssl"
CERT_FILE="$SSL_DIR/cert.pem"
KEY_FILE="$SSL_DIR/key.pem"
CSR_FILE="$SSL_DIR/cert.csr"
CONFIG_FILE="$SSL_DIR/openssl.conf"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
}

# 检查命令是否存在
check_command() {
    if ! command -v $1 &> /dev/null; then
        log_error "Command '$1' not found"
        exit 1
    fi
}

# 创建SSL目录
create_ssl_dir() {
    log_info "Creating SSL directory..."
    mkdir -p "$SSL_DIR"
    chmod 700 "$SSL_DIR"
}

# 生成OpenSSL配置
generate_openssl_config() {
    log_info "Generating OpenSSL configuration..."
    
    cat > "$CONFIG_FILE" << EOF
[req]
default_bits = 2048
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
prompt = no

[dn]
C = CN
ST = Beijing
L = Beijing
O = Offline Language Player
OU = IT Department
CN = $DOMAIN
emailAddress = admin@$DOMAIN

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = $DOMAIN
DNS.2 = localhost
DNS.3 = 127.0.0.1
DNS.4 = *.localhost
IP.1 = 127.0.0.1
IP.2 = ::1
EOF
    
    log_info "OpenSSL configuration generated: $CONFIG_FILE"
}

# 生成自签名证书
generate_self_signed_cert() {
    log_info "Generating self-signed SSL certificate..."
    
    # 生成私钥
    log_info "Generating private key..."
    openssl genrsa -out "$KEY_FILE" 2048
    chmod 600 "$KEY_FILE"
    
    # 生成证书签名请求
    log_info "Generating certificate signing request..."
    openssl req -new -key "$KEY_FILE" -out "$CSR_FILE" -config "$CONFIG_FILE"
    
    # 生成自签名证书
    log_info "Generating self-signed certificate..."
    openssl x509 -req -days 365 -in "$CSR_FILE" -signkey "$KEY_FILE" -out "$CERT_FILE" -extensions v3_req -extfile "$CONFIG_FILE"
    
    # 清理临时文件
    rm -f "$CSR_FILE"
    
    log_info "Self-signed certificate generated successfully"
    log_info "Certificate: $CERT_FILE"
    log_info "Private key: $KEY_FILE"
}

# 设置Let's Encrypt证书
setup_letsencrypt() {
    log_info "Setting up Let's Encrypt certificate for domain: $DOMAIN"
    
    # 检查域名是否可解析
    if ! nslookup "$DOMAIN" &> /dev/null; then
        log_error "Domain $DOMAIN is not resolvable"
        exit 1
    fi
    
    # 安装certbot
    if ! command -v certbot &> /dev/null; then
        log_info "Installing certbot..."
        if command -v apt-get &> /dev/null; then
            apt-get update
            apt-get install -y certbot python3-certbot-nginx
        elif command -v yum &> /dev/null; then
            yum install -y certbot python3-certbot-nginx
        elif command -v dnf &> /dev/null; then
            dnf install -y certbot python3-certbot-nginx
        else
            log_error "Unsupported package manager for certbot installation"
            exit 1
        fi
    fi
    
    # 获取证书
    log_info "Obtaining Let's Encrypt certificate..."
    certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos --email "admin@$DOMAIN"
    
    # 设置自动续期
    log_info "Setting up automatic certificate renewal..."
    (crontab -l 2>/dev/null; echo "0 12 * * * /usr/bin/certbot renew --quiet") | crontab -
    
    log_info "Let's Encrypt certificate setup completed"
}

# 验证证书
verify_certificate() {
    log_info "Verifying SSL certificate..."
    
    if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
        log_error "Certificate files not found"
        return 1
    fi
    
    # 检查证书格式
    if ! openssl x509 -in "$CERT_FILE" -text -noout &> /dev/null; then
        log_error "Invalid certificate format"
        return 1
    fi
    
    # 检查私钥格式
    if ! openssl rsa -in "$KEY_FILE" -check &> /dev/null; then
        log_error "Invalid private key format"
        return 1
    fi
    
    # 检查证书和私钥是否匹配
    cert_md5=$(openssl x509 -noout -modulus -in "$CERT_FILE" | openssl md5)
    key_md5=$(openssl rsa -noout -modulus -in "$KEY_FILE" | openssl md5)
    
    if [ "$cert_md5" != "$key_md5" ]; then
        log_error "Certificate and private key do not match"
        return 1
    fi
    
    # 显示证书信息
    log_info "Certificate information:"
    openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Issuer:|Not Before:|Not After:)"
    
    log_info "Certificate verification passed"
    return 0
}

# 生成DH参数
generate_dh_params() {
    log_info "Generating DH parameters..."
    
    DH_FILE="$SSL_DIR/dhparam.pem"
    
    if [ -f "$DH_FILE" ]; then
        log_info "DH parameters already exist: $DH_FILE"
        return 0
    fi
    
    openssl dhparam -out "$DH_FILE" 2048
    chmod 600 "$DH_FILE"
    
    log_info "DH parameters generated: $DH_FILE"
}

# 创建证书链文件
create_cert_chain() {
    log_info "Creating certificate chain..."
    
    CHAIN_FILE="$SSL_DIR/chain.pem"
    
    if [ ! -f "$CERT_FILE" ]; then
        log_error "Certificate file not found"
        return 1
    fi
    
    cp "$CERT_FILE" "$CHAIN_FILE"
    
    log_info "Certificate chain created: $CHAIN_FILE"
}

# 设置证书权限
set_cert_permissions() {
    log_info "Setting certificate permissions..."
    
    chmod 600 "$KEY_FILE"
    chmod 644 "$CERT_FILE"
    chmod 644 "$SSL_DIR"/*.pem
    
    # 设置目录权限
    chmod 700 "$SSL_DIR"
    
    log_info "Certificate permissions set"
}

# 显示证书信息
show_certificate_info() {
    log_info "Certificate Information:"
    echo "=========================="
    
    if [ -f "$CERT_FILE" ]; then
        echo "Certificate: $CERT_FILE"
        openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Issuer:|Not Before:|Not After:|DNS:)"
        echo ""
    fi
    
    if [ -f "$KEY_FILE" ]; then
        echo "Private Key: $KEY_FILE"
        openssl rsa -in "$KEY_FILE" -text -noout | grep -E "(modulus|publicExponent):"
        echo ""
    fi
    
    if [ -f "$SSL_DIR/dhparam.pem" ]; then
        echo "DH Parameters: $SSL_DIR/dhparam.pem"
        openssl dhparam -in "$SSL_DIR/dhparam.pem" -text -noout | grep -E "(prime|generator):"
        echo ""
    fi
}

# 备份证书
backup_certificates() {
    log_info "Backing up certificates..."
    
    BACKUP_DIR="$SSL_DIR/backup/$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$BACKUP_DIR"
    
    if [ -f "$CERT_FILE" ]; then
        cp "$CERT_FILE" "$BACKUP_DIR/"
    fi
    
    if [ -f "$KEY_FILE" ]; then
        cp "$KEY_FILE" "$BACKUP_DIR/"
    fi
    
    if [ -f "$CONFIG_FILE" ]; then
        cp "$CONFIG_FILE" "$BACKUP_DIR/"
    fi
    
    if [ -f "$SSL_DIR/dhparam.pem" ]; then
        cp "$SSL_DIR/dhparam.pem" "$BACKUP_DIR/"
    fi
    
    log_info "Certificates backed up to: $BACKUP_DIR"
}

# 清理证书
cleanup_certificates() {
    log_info "Cleaning up old certificates..."
    
    # 清理备份文件（保留最近5个）
    find "$SSL_DIR/backup" -mindepth 1 -maxdepth 1 -type d | sort -r | tail -n +6 | xargs rm -rf 2>/dev/null || true
    
    log_info "Old certificates cleaned up"
}

# 显示帮助信息
show_help() {
    echo "SSL/TLS Certificate Setup Script"
    echo ""
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  -d, --domain DOMAIN       Set domain name (default: localhost)"
    echo "  -s, --self-signed         Generate self-signed certificate"
    echo "  -l, --letsencrypt          Setup Let's Encrypt certificate"
    echo "  -v, --verify              Verify certificate"
    echo "  -i, --info                Show certificate information"
    echo "  -b, --backup              Backup certificates"
    echo "  -c, --cleanup             Clean up old certificates"
    echo "  -h, --help                Show this help message"
    echo ""
    echo "Environment Variables:"
    echo "  DOMAIN                      Domain name for certificate"
    echo ""
    echo "Examples:"
    echo "  $0 --self-signed                    # Generate self-signed certificate"
    echo "  $0 --letsencrypt                    # Setup Let's Encrypt certificate"
    echo "  $0 --domain example.com --self-signed  # Generate for specific domain"
    echo "  $0 --verify                        # Verify existing certificate"
    echo "  $0 --info                          # Show certificate info"
}

# 主函数
main() {
    local action=""
    local domain="$DOMAIN"
    
    # 解析命令行参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            -d|--domain)
                domain="$2"
                shift 2
                ;;
            -s|--self-signed)
                action="self-signed"
                shift
                ;;
            -l|--letsencrypt)
                action="letsencrypt"
                shift
                ;;
            -v|--verify)
                action="verify"
                shift
                ;;
            -i|--info)
                action="info"
                shift
                ;;
            -b|--backup)
                action="backup"
                shift
                ;;
            -c|--cleanup)
                action="cleanup"
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                show_help
                exit 1
                ;;
        esac
    done
    
    # 设置域名
    if [ -n "$domain" ]; then
        DOMAIN="$domain"
    fi
    
    # 检查必要的命令
    check_command openssl
    
    # 创建SSL目录
    create_ssl_dir
    
    # 执行相应操作
    case $action in
        "self-signed")
            log_info "Generating self-signed certificate for domain: $DOMAIN"
            generate_openssl_config
            generate_self_signed_cert
            generate_dh_params
            create_cert_chain
            set_cert_permissions
            verify_certificate
            show_certificate_info
            ;;
        "letsencrypt")
            log_info "Setting up Let's Encrypt certificate for domain: $DOMAIN"
            setup_letsencrypt
            verify_certificate
            show_certificate_info
            ;;
        "verify")
            verify_certificate
            ;;
        "info")
            show_certificate_info
            ;;
        "backup")
            backup_certificates
            ;;
        "cleanup")
            cleanup_certificates
            ;;
        "")
            log_warn "No action specified. Use --help for usage information."
            show_help
            exit 1
            ;;
        *)
            log_error "Unknown action: $action"
            show_help
            exit 1
            ;;
    esac
}

# 运行主函数
main "$@"
